{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "55a4e90c",
   "metadata": {},
   "source": [
    "## Flask介绍\n",
    "![](01_Flask基础_images/1.png)\n",
    "Flask和相应的插件写得很好，扩展列表：http://flask.pocoo.org/extensions/\n",
    "\n",
    "中文文档（http://docs.jinkan.org/docs/flask/）"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "78ee6fc1",
   "metadata": {},
   "source": [
    "## 第一个Flask程序"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "9d3eccfc",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T15:22:41.179509Z",
     "start_time": "2023-10-13T15:21:58.146303Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on http://127.0.0.1:8000/ (Press CTRL+C to quit)\n",
      "127.0.0.1 - - [13/Oct/2023 23:22:05] \"GET / HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [13/Oct/2023 23:22:06] \"GET /favicon.ico HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [13/Oct/2023 23:22:18] \"GET /index HTTP/1.1\" 200 -\n"
     ]
    }
   ],
   "source": [
    "\"\"\"第一个flask程序\"\"\"\n",
    "from flask import Flask\n",
    "\n",
    "# 创建 Flask对象\n",
    "app = Flask(__name__)\n",
    "\n",
    "# 路由的地址\n",
    "@app.route('/index')\n",
    "def index():\n",
    "    # return 代表将数据返回给浏览器\n",
    "    return '北理工-Python'\n",
    "\n",
    "\n",
    "if __name__ ==\"__main__\":\n",
    "    # 启动 web应用服务, 默认端口号是5000，我们可以修改端口号\n",
    "    app.run(port=8000)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c363e67",
   "metadata": {},
   "source": [
    "## Flask启动的参数设置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c8033dd5",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T15:27:16.332884Z",
     "start_time": "2023-10-13T15:27:05.616022Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on all addresses.\n",
      "   WARNING: This is a development server. Do not use it in a production deployment.\n",
      " * Running on http://10.197.133.24:8000/ (Press CTRL+C to quit)\n",
      "10.197.133.24 - - [13/Oct/2023 23:27:09] \"GET / HTTP/1.1\" 200 -\n",
      "10.197.133.24 - - [13/Oct/2023 23:27:09] \"GET /favicon.ico HTTP/1.1\" 404 -\n"
     ]
    }
   ],
   "source": [
    "from flask import Flask\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "@app.route('/')\n",
    "def index():\n",
    "    return \"Hello!!\"\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "\n",
    "    # 运行程序时，可以指定运行的主机IP地址，端口\n",
    "    # 如果想在同一个局域网下的其他电脑访问自己电脑上的 Flask网站，需要设置 host='0.0.0.0' 才能访问得到\n",
    "    app.run(host='0.0.0.0', port=8000)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1fd437d3",
   "metadata": {},
   "source": [
    "## Debug模式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "c78cb54d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T15:44:29.855837Z",
     "start_time": "2023-10-13T15:44:06.216790Z"
    },
    "collapsed": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n",
      "[2023-10-13 23:44:09,010] ERROR in app: Exception on / [GET]\n",
      "Traceback (most recent call last):\n",
      "  File \"/Users/macbook/opt/anaconda3/lib/python3.9/site-packages/flask/app.py\", line 2447, in wsgi_app\n",
      "    response = self.full_dispatch_request()\n",
      "  File \"/Users/macbook/opt/anaconda3/lib/python3.9/site-packages/flask/app.py\", line 1952, in full_dispatch_request\n",
      "    rv = self.handle_user_exception(e)\n",
      "  File \"/Users/macbook/opt/anaconda3/lib/python3.9/site-packages/flask/app.py\", line 1821, in handle_user_exception\n",
      "    reraise(exc_type, exc_value, tb)\n",
      "  File \"/Users/macbook/opt/anaconda3/lib/python3.9/site-packages/flask/_compat.py\", line 39, in reraise\n",
      "    raise value\n",
      "  File \"/Users/macbook/opt/anaconda3/lib/python3.9/site-packages/flask/app.py\", line 1950, in full_dispatch_request\n",
      "    rv = self.dispatch_request()\n",
      "  File \"/Users/macbook/opt/anaconda3/lib/python3.9/site-packages/flask/app.py\", line 1936, in dispatch_request\n",
      "    return self.view_functions[rule.endpoint](**req.view_args)\n",
      "  File \"/var/folders/0q/2y7xgmvn00b1090yx3d_n1140000gn/T/ipykernel_34342/1060600272.py\", line 11, in index\n",
      "    c = a/b\n",
      "ZeroDivisionError: division by zero\n",
      "127.0.0.1 - - [13/Oct/2023 23:44:09] \"GET / HTTP/1.1\" 500 -\n"
     ]
    }
   ],
   "source": [
    "\"\"\"在jupyter notebook中，不要使用Debug模式\"\"\"\n",
    "from flask import Flask\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "\n",
    "@app.route('/')\n",
    "def index():\n",
    "    a = 1\n",
    "    b = 0\n",
    "    c = a/b\n",
    "    return 'Hello Python 123456'\n",
    "\n",
    "# DEBUG的好处是：\n",
    "# 1.可以热加载，更新完代码后，不用手动重新启动服务，系统会自动给我们重启\n",
    "# 2.可以直接把错误信息加载到浏览器\n",
    "\n",
    "if __name__ =='__main__':\n",
    "    # 开启 Debug模式\n",
    "    \n",
    "    app.debug = True\n",
    "    app.run()\n",
    "    # 或者：app.run(debug=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eab0283f",
   "metadata": {},
   "source": [
    "## URL与函数的映射(动态路由)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a60d3b4",
   "metadata": {},
   "source": [
    "![](01_Flask基础_images/2.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2a5aa917",
   "metadata": {},
   "source": [
    "**URL路径参数:**\n",
    "\n",
    "比如，有一个请求访问的接口地址为 /users/11001 ，其中 11001 实际上为具体的请求参数，表明请求 11001 号用户的信息。\n",
    "\n",
    "此时如何从url中提取出 11001 的数据？"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d8e3af0d",
   "metadata": {},
   "source": [
    "![](01_Flask基础_images/3.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6855bf7a",
   "metadata": {},
   "source": [
    "其中 <user_id> ，尖括号是固定写法，语法为 ， variable 默认的数据类型是字符串。\n",
    "\n",
    "如果需要指定类型，则要写成 converter:variable ，其中converter 就是类型名称，可以有以下几种：\n",
    "- string: 如果没有指定具体的数据类型，那么默认就是使用 string 数据类型。\n",
    "- int: 数据类型只能传递 int 类型。\n",
    "- float: 数据类型只能传递 float 类型。\n",
    "- path: 数据类型和 string 有点类似，都是可以接收任意的字符串，但是 path 可以接收路径，也就是说可以包含斜杠。\n",
    "- uuid: 数据类型只能接收符合 uuid 的字符串。 uuid 是一个全宇宙都唯一的字符串，一般可以用来作为表的主键。\n",
    "- any: 数据类型可以在一个 url 中指定多个路径。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "5cde76f7",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T15:53:32.040367Z",
     "start_time": "2023-10-13T15:53:13.011498Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n",
      "127.0.0.1 - - [13/Oct/2023 23:53:16] \"GET / HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [13/Oct/2023 23:53:24] \"GET /12345 HTTP/1.1\" 200 -\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "接收到的文章ID是：12345\n"
     ]
    }
   ],
   "source": [
    "\"\"\"动态路由\"\"\"\n",
    "from flask import Flask\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# @app.route('/article/details/86714886')\n",
    "# def index1():\n",
    "#     return '/article/details/86714886'\n",
    "\n",
    "# @app.route('/article/details/103582822')\n",
    "# def index2():\n",
    "#     return '/article/details/103582822'\n",
    "\n",
    "@app.route('/<id>')\n",
    "def index(id):\n",
    "    print(f'接收到的文章ID是：{id}')\n",
    "    \n",
    "    # 获取到ID后，去数据库查询数据\n",
    "    return f'返回了，{id}的文章'\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "b8bc71c0",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T15:58:33.471275Z",
     "start_time": "2023-10-13T15:57:59.013787Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on all addresses.\n",
      "   WARNING: This is a development server. Do not use it in a production deployment.\n",
      " * Running on http://10.197.133.24:8000/ (Press CTRL+C to quit)\n",
      "10.197.133.24 - - [13/Oct/2023 23:58:06] \"GET / HTTP/1.1\" 404 -\n",
      "10.197.133.24 - - [13/Oct/2023 23:58:27] \"GET /float/1.5 HTTP/1.1\" 200 -\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "接收到的文章ID是：1.5\n",
      "<class 'float'>\n"
     ]
    }
   ],
   "source": [
    "\"\"\"动态 URL 参数的类型\"\"\"\n",
    "\n",
    "from flask import Flask\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "@app.route('/article/<id>')\n",
    "def index(id):\n",
    "    \n",
    "    print(f'接收到的文章ID是：{id}')\n",
    "    print(type(id))\n",
    "    return f'返回了，{id}的文章'\n",
    "\n",
    "\n",
    "@app.route('/int/<int:id>')\n",
    "def index_int(id):\n",
    "    \n",
    "    print(f'接收到的文章ID是：{id}')\n",
    "    print(type(id))\n",
    "    return f'返回了，{id}的文章'\n",
    "\n",
    "\n",
    "@app.route('/float/<float:id>')\n",
    "def index_float(id):\n",
    "    \n",
    "    print(f'接收到的文章ID是：{id}')\n",
    "    print(type(id))\n",
    "    return f'返回了，{id}的文章'\n",
    "\n",
    "\n",
    "@app.route('/str/<string:id>')\n",
    "def index_str(id):\n",
    "    \n",
    "    print(f'接收到的文章ID是：{id}')\n",
    "    print(type(id))\n",
    "    return f'返回了，{id}的文章'\n",
    "\n",
    "\n",
    "@app.route('/path/<path:id>')\n",
    "def index_path(id):\n",
    "    \n",
    "    print(f'接收到的文章ID是：{id}')\n",
    "    print(type(id))\n",
    "    return f'返回了，{id}的文章'\n",
    "\n",
    "@app.route('/uuid/<uuid:id>')\n",
    "def index_uuid(id):\n",
    "    \n",
    "    print(f'接收到的文章ID是：{id}')\n",
    "    print(type(id))\n",
    "    return f'返回了，{id}的文章'\n",
    "\n",
    "@app.route('/<any(user,item):tmp>/<int:id>')\n",
    "def index_any(tmp,id):\n",
    "    if tmp == 'user':\n",
    "        return f'返回了一个编号为 {id} 的 用户 信息'\n",
    "    elif tmp =='item':\n",
    "        return f'返回了一个编号为 {id} 的 元素 信息'\n",
    "\n",
    "from werkzeug.routing import BaseConverter\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    \n",
    "    # 让同一局域网内的电脑也可以访问\n",
    "    app.run(host='0.0.0.0', port=8000)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f8bb163",
   "metadata": {},
   "source": [
    "## 自定义转换器"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d92d85f2",
   "metadata": {},
   "source": [
    "**为什么路径参数可以直接识别数据类型？**\n",
    "\n",
    "- 从 werkzeug.routing 导入 BaseConverter 类 了解底层\n",
    "- int 路径参数底层调用 IntegerConverter 类来作格式判断\n",
    "- float 路径参数底层调用 FloatConverter 类来作格式判断\n",
    "- string 路径参数底层调用 StringConverter 类来作格式判断\n",
    "- 如果遇到需要匹配提取 /sms_codes/1688888888 中的手机号数据，Flask内置的转换器就无法满足需求，此时需要自定义转换器。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1abe0a66",
   "metadata": {},
   "source": [
    "### 定义方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "54930c74",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T16:05:29.720205Z",
     "start_time": "2023-10-13T16:04:14.620771Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on all addresses.\n",
      "   WARNING: This is a development server. Do not use it in a production deployment.\n",
      " * Running on http://10.197.133.24:8000/ (Press CTRL+C to quit)\n",
      "10.197.133.24 - - [14/Oct/2023 00:04:17] \"GET / HTTP/1.1\" 200 -\n",
      "10.197.133.24 - - [14/Oct/2023 00:04:17] \"GET /apple-touch-icon-precomposed.png HTTP/1.1\" 404 -\n",
      "10.197.133.24 - - [14/Oct/2023 00:04:17] \"GET /apple-touch-icon.png HTTP/1.1\" 404 -\n",
      "10.197.133.24 - - [14/Oct/2023 00:04:22] \"GET / HTTP/1.1\" 200 -\n",
      "10.197.133.24 - - [14/Oct/2023 00:04:28] \"GET /18370942865 HTTP/1.1\" 200 -\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "18370942865\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "10.197.133.24 - - [14/Oct/2023 00:05:24] \"GET / HTTP/1.1\" 200 -\n"
     ]
    }
   ],
   "source": [
    "from flask import Flask\n",
    "from werkzeug.routing import BaseConverter\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# 第一步：创建转换器类，保存匹配时的正则表达式\n",
    "class PhoneConverter(BaseConverter):\n",
    "    \"\"\"识别手机号码\"\"\"\n",
    "    \n",
    "    # regex 名字是固定的\n",
    "    regex = '1[3-9]\\d{9}'\n",
    "\n",
    "# 第二步：将自定义的转换器告知 Flask应用\n",
    "app.url_map.converters['phone'] = PhoneConverter\n",
    "\n",
    "@app.route('/')\n",
    "def index():\n",
    "    return \"Hello\"\n",
    "\n",
    "# 第三步：在使用转换器的地方定义使用\n",
    "@app.route('/<phone:param>')\n",
    "def phone(param):\n",
    "    print(param)\n",
    "    return f\"您传递的手机号是：{param}\"\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run(host='0.0.0.0', port=8000)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "43d7e926",
   "metadata": {},
   "source": [
    "### to_python\n",
    "在转换器类中，实现 to_python(self,value) 方法，这个方法的返回值，将会传递到 view函数中作为参数\n",
    "\n",
    "### to_url\n",
    "在转换器类中，实现 to_url(self,values) 方法，这个方法的返回值，将会在调用url_for函数的时候生成符合要求的URL形式。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "10f8ed4b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T16:10:11.557232Z",
     "start_time": "2023-10-13T16:09:36.124195Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on all addresses.\n",
      "   WARNING: This is a development server. Do not use it in a production deployment.\n",
      " * Running on http://10.197.133.24:8000/ (Press CTRL+C to quit)\n",
      "10.197.133.24 - - [14/Oct/2023 00:09:39] \"GET / HTTP/1.1\" 200 -\n",
      "10.197.133.24 - - [14/Oct/2023 00:09:45] \"GET / HTTP/1.1\" 200 -\n",
      "10.197.133.24 - - [14/Oct/2023 00:10:01] \"GET /user_info/uer+13 HTTP/1.1\" 200 -\n"
     ]
    }
   ],
   "source": [
    "from flask import Flask\n",
    "from werkzeug.routing import BaseConverter\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# 需求：路径参数传递多信息并以一个参数接收。\n",
    "# 比如：获取姓名：zs 年龄 18的信息\n",
    "# /user/zs+18\n",
    "\n",
    "# 自定义转换器\n",
    "class LiConverter(BaseConverter):\n",
    "    \n",
    "    def to_python(self, value):\n",
    "        \n",
    "        # 返回一个列表\n",
    "        return value.split('+')\n",
    "\n",
    "    \n",
    "# 将转换器 与 app关联\n",
    "app.url_map.converters['li'] = LiConverter\n",
    "\n",
    "@app.route('/')\n",
    "def index():\n",
    "    return \"Hello\"\n",
    "\n",
    "\n",
    "@app.route('/user/<info>')\n",
    "def user(info):\n",
    "    args = info.split('+')\n",
    "    return f'获取了某某信息！！{args}'\n",
    "\n",
    "\n",
    "@app.route('/user_info/<li:info>')\n",
    "def user_info(info):\n",
    "    return f'获取了某某信息！！{info}'\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run(host='0.0.0.0', port=8000)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ff735567",
   "metadata": {},
   "source": [
    "## 查询参数的获取"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "6e6786b0",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T16:13:55.254818Z",
     "start_time": "2023-10-13T16:13:29.505008Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET / HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /?uname=python&pwd=ok HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /apple-touch-icon-precomposed.png HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /apple-touch-icon-precomposed.png HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /apple-touch-icon.png HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /apple-touch-icon.png HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /favicon.ico HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /apple-touch-icon-precomposed.png HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /apple-touch-icon.png HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /favicon.ico HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /?uname=python&pwd=ok HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /apple-touch-icon-precomposed.png HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /apple-touch-icon.png HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /favicon.ico HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /apple-touch-icon-precomposed.png HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /apple-touch-icon.png HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:31] \"GET /favicon.ico HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:13:47] \"GET /test/?uname=python&pwd=ok HTTP/1.1\" 200 -\n"
     ]
    }
   ],
   "source": [
    "from flask import Flask,request\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# http://127.0.0.1:5000/test/?uname=python&pwd=ok\n",
    "\n",
    "@app.route('/test/')\n",
    "def index():\n",
    "    # 方式1：\n",
    "    # uname = request.args.get('uname')\n",
    "    # pwd = request.args.get('pwd')\n",
    "\n",
    "    # 方式2：\n",
    "    uname = request.values.get('uname')\n",
    "    pwd = request.values.get('pwd')\n",
    "\n",
    "    return f'Hello! === {uname} === {pwd}'\n",
    "\n",
    "if __name__ =='__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a8e2cf4",
   "metadata": {},
   "source": [
    "## 请求体参数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d17350f8",
   "metadata": {},
   "source": [
    "![](01_Flask基础_images/4.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "27bfd5aa",
   "metadata": {},
   "outputs": [],
   "source": [
    "from flask import Flask, request\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "\n",
    "@app.route('/login', methods=['POST', 'GET'])\n",
    "def login():\n",
    "    # 方式1：\n",
    "    # uname = request.form.get('uname')\n",
    "    # pwd = request.form.get('pwd')\n",
    "\n",
    "    # 方法2：\n",
    "    uname = request.values.get('uname')\n",
    "    pwd = request.values.get('pwd')\n",
    "\n",
    "    return f'Hello! == {uname} == {pwd} '\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5ee2eb43",
   "metadata": {},
   "source": [
    "## 上传文件"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "df8dc309",
   "metadata": {},
   "source": [
    "![](01_Flask基础_images/5.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c12f2a48",
   "metadata": {},
   "outputs": [],
   "source": [
    "from flask import Flask,request\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "@app.route('/upload',methods=['POST'])\n",
    "def upload():\n",
    "\n",
    "    # 获取客户端传来的对象\n",
    "    f = request.files.get('pic')\n",
    "    \n",
    "    # 获取文件名\n",
    "    fname = f.filename\n",
    "    \n",
    "    # 写文件\n",
    "    with open(f'./imgs/{fname}','wb') as tf:\n",
    "        tf.write(f.read())\n",
    "    \n",
    "    # 返回网页信息\n",
    "    return f'上传成功！！'\n",
    "\n",
    "if __name__ =='__main__':\n",
    "    app.run(debug=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba1661cc",
   "metadata": {},
   "source": [
    "## 获取其它参数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2dd814cf",
   "metadata": {},
   "source": [
    "如果想要获取其他地方传递的参数，可以通过Flask提供的request对象来读取。\n",
    "\n",
    "不同位置的参数都存放在request的不同属性中：\n",
    "\n",
    "![](01_Flask基础_images/6.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "6a98f7b6",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T16:25:32.496217Z",
     "start_time": "2023-10-13T16:25:01.058458Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n",
      "127.0.0.1 - - [14/Oct/2023 00:25:03] \"GET / HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:25:11] \"GET /args HTTP/1.1\" 200 -\n"
     ]
    }
   ],
   "source": [
    "from flask import Flask, request\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "\n",
    "@app.route('/args', methods=['GET', 'POST'])\n",
    "def args():\n",
    "    \n",
    "    # 获取请求的 URL地址\n",
    "    url = request.url\n",
    "    \n",
    "    # 获取请求的 HTTP方法\n",
    "    method = request.method\n",
    "    \n",
    "    # 获取请求头信息\n",
    "    headers = request.headers.get('Content-Type')\n",
    "    user_agent = request.headers.get('User-Agent')\n",
    "    \n",
    "    # 获取cookies中的信息\n",
    "    uid = request.cookies.get('uid')\n",
    "    return f'Hello == {url} == {method} == {headers} == {user_agent} == {uid}'\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30546d3f",
   "metadata": {},
   "source": [
    "## url_for 函数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa720e6e",
   "metadata": {},
   "source": [
    "![](01_Flask基础_images/7.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "89266335",
   "metadata": {},
   "source": [
    "一般我们通过一个 URL就可以执行到某一个函数。如果反过来, 我们知道一个函数, 怎么去获得这个 URL呢？\n",
    "\n",
    "url_for 函数就可以帮我们实现这个功能。\n",
    "\n",
    "**注意:**\n",
    "- url_for 函数可以接收1个及以上的参数，他接收函数名作为第一个参数\n",
    "- 如果还出现其他的参数，则会添加到 URL 的后面作为查询参数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "4e4ddf4d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T16:33:51.623403Z",
     "start_time": "2023-10-13T16:33:26.384493Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n",
      "127.0.0.1 - - [14/Oct/2023 00:33:33] \"GET / HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:33:43] \"GET /show_url HTTP/1.1\" 200 -\n"
     ]
    }
   ],
   "source": [
    "from flask import Flask, url_for\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "\n",
    "@app.route('/index/')\n",
    "def index():\n",
    "    return f'Hello !!'\n",
    "\n",
    "\n",
    "@app.route('/home/<int:uid>/')\n",
    "def home(uid):\n",
    "    return f'Hello !!{uid}'\n",
    "\n",
    "\n",
    "@app.route('/show_url')\n",
    "def show_url():\n",
    "    \n",
    "    # 第1个参数是函数的名字，第2个参数默认开始匹配路径参数，匹配不上就会以查询参数进行传递\n",
    "    url = url_for('home', uid=1001, addr='beijing')\n",
    "\n",
    "    return f'反向查找到的URL地址：{url}'\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "966d2210",
   "metadata": {},
   "source": [
    "**使用url_for函数原因**\n",
    "\n",
    "![](01_Flask基础_images/8.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "e9c809cd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-13T16:37:41.472798Z",
     "start_time": "2023-10-13T16:36:52.509018Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n",
      "127.0.0.1 - - [14/Oct/2023 00:36:54] \"GET / HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 00:37:01] \"GET /show_url HTTP/1.1\" 200 -\n"
     ]
    }
   ],
   "source": [
    "from flask import Flask, url_for\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "\n",
    "@app.route('/index/')\n",
    "def index():\n",
    "    return f'Hello !!'\n",
    "\n",
    "\n",
    "@app.route('/show_url')\n",
    "def show_url():\n",
    "    url = url_for('index', \n",
    "                  next='/') # 作为查询参数传递\n",
    "    \n",
    "    return f'反向找到的url地址是：{url}'\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "889a027d",
   "metadata": {},
   "source": [
    "技巧：在定义url的时候，一定要记得在最后加一个斜杠。\n",
    "1. 如果不加斜杠，那么在浏览器中访问这个url的时候，如果最后加了斜杠，那么就访问不到。这样用户体验不太好。\n",
    "2. 搜索引擎会将不加斜杠的和加斜杠的视为两个不同的url。而其实加和不加斜杠的都是同一个url，那么就会给搜索引擎造成一个误解。加了斜杠，就不会出现没有斜杠的情况"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6cfc6b0d",
   "metadata": {},
   "source": [
    "## 响应-重定向"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ea6a93a6",
   "metadata": {},
   "source": [
    "![](01_Flask基础_images/9.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7bc1eee8",
   "metadata": {},
   "source": [
    "**永久性重定向：**\n",
    "\n",
    "http 的状态码是 301, 多用于旧网址被废弃了要转到一个新的网址确保用户的访问\n",
    "\n",
    "比如：你输入 www.jingdong.com 的时候，会被重定向到 www.jd.com ，因为 jingdong.com 这个网址已经被废弃了，被改成 jd.com所以这种情况下应该用永久重定向"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0902bf6e",
   "metadata": {},
   "source": [
    "**暂时性重定向：**\n",
    "\n",
    "http 的状态码是 302,表示页面的暂时性跳转。\n",
    "\n",
    "比如：访问一个需要权限的网址，如果当前用户没有登录，应该重定向到登录页面，这种情况下，应该用暂时性重定向"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "145785d5",
   "metadata": {},
   "source": [
    "**flask中重定向：**\n",
    "\n",
    "重定向是通过 redirect(location,code=302) 这个函数来实现的, location表示需要重定向到的 URL, 应该配合之前讲的 url_for() 函数来使用，code 表示采用哪个重定向，默认是 302 也即 暂时性重定向, 可以修改成 301 来实现永久性重定向"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "520ba641",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-14T02:49:41.082175Z",
     "start_time": "2023-10-14T02:49:22.754945Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n",
      "127.0.0.1 - - [14/Oct/2023 10:49:25] \"GET / HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 10:49:33] \"GET /info HTTP/1.1\" 308 -\n",
      "127.0.0.1 - - [14/Oct/2023 10:49:33] \"GET /info/ HTTP/1.1\" 301 -\n",
      "127.0.0.1 - - [14/Oct/2023 10:49:33] \"GET /user_login/ HTTP/1.1\" 200 -\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=====================这个是个人信息=======================\n"
     ]
    }
   ],
   "source": [
    "from flask import Flask,redirect,url_for\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "@app.route('/user_login/')\n",
    "def login():\n",
    "    return f'登录页面 !!'\n",
    "\n",
    "@app.route('/info/')\n",
    "def info():\n",
    "    print('=====================这个是个人信息=======================')\n",
    "    \n",
    "    # 重定向 和 url_for结合使用\n",
    "    return redirect(url_for('login'), code=301)  \n",
    "\n",
    "\n",
    "if __name__ =='__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c2e05127",
   "metadata": {},
   "source": [
    "## 响应-响应内容"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6098d70e",
   "metadata": {},
   "source": [
    "![](01_Flask基础_images/10.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "cdd220e2",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-14T02:57:06.353159Z",
     "start_time": "2023-10-14T02:55:48.494091Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n",
      "127.0.0.1 - - [14/Oct/2023 10:55:50] \"GET / HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 10:55:55] \"GET /json2 HTTP/1.1\" 200 -\n",
      "127.0.0.1 - - [14/Oct/2023 10:55:56] \"GET /json1 HTTP/1.1\" 200 -\n"
     ]
    }
   ],
   "source": [
    "from flask import jsonify\n",
    "from flask import Flask\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# 返回字符串\n",
    "@app.route('/str')\n",
    "def index():\n",
    "    return '你好,少年'\n",
    "\n",
    "\n",
    "# 返回json\n",
    "app.config['JSON_AS_ASCII'] = False # 显示汉字，不显示汉字的 ASCII码\n",
    "@app.route('/json1')\n",
    "def r_json():\n",
    "    return {'key': 'python语言'}\n",
    "\n",
    "\n",
    "@app.route('/json2')\n",
    "def r_json2():\n",
    "    return jsonify({'key': 'python语言'})\n",
    "\n",
    "\n",
    "# 可以返回一个元组，元组中必须至少包含一个项目，\n",
    "# 且项目应当由(response, status)、(response, headers) 或者 (response, status, headers) 组成。\n",
    "# status 的值会重载状态代码， headers 是一个由额外头部值组成的列表 或字典\n",
    "# status 值会覆盖状态代码， headers 可以是一个列表或字典，作为额外的消息标头值。\n",
    "@app.route('/tuple')\n",
    "def r_tuple():\n",
    "\n",
    "    # return 'tuple',202\n",
    "    # return 'tuple',{'itbaizhan':'python'}\n",
    "    # return 'tuple',300,{'itbaizhan':'python'}\n",
    "    return 'tuple', 300, [('itbaizhan', 'python_sql')]\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9c63a6e3",
   "metadata": {},
   "source": [
    "## 响应-自定义响应"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "4f92c368",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-14T02:59:52.183725Z",
     "start_time": "2023-10-14T02:59:23.574913Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n",
      "127.0.0.1 - - [14/Oct/2023 10:59:24] \"GET / HTTP/1.1\" 404 -\n",
      "127.0.0.1 - - [14/Oct/2023 10:59:39] \"GET /home HTTP/1.1\" 404 -\n"
     ]
    }
   ],
   "source": [
    "from flask import Flask,Response,make_response\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "@app.route('/')\n",
    "def index():\n",
    "    \"\"\"创建 Response\"\"\"\n",
    "    \n",
    "    # return Response('你好，少年！！',status=500,headers={'itbaizhan':'python!!!'})\n",
    "    # return Response('')\n",
    "    return Response('无法找到页面', status=404)\n",
    "\n",
    "\n",
    "@app.route('/home')\n",
    "def home():\n",
    "    \"\"\"make_response方式\"\"\"\n",
    "    \n",
    "    resp = make_response('这个是创建的Response对象')\n",
    "    resp.headers['itbaizhan']='SQL+Python+Flask'\n",
    "    resp.status = '404 not found'\n",
    "    return resp\n",
    "\n",
    "if __name__ =='__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6641c086",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "162f3885",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.12"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "287.995px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
